package com.wechat.common.security.token;

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;

@Slf4j
@Component
public class TokenUtil {

    private static final String TOKEN_TYPE_ACCESS = "access_token";
    private static final String TOKEN_TYPE_REFRESH = "refresh_token";
    @Value("${jwt.secret:wechat_secret_key_2024}")
    private String secret;
    @Value("${jwt.timeout:86400000}") // 默认24小时（毫秒）
    private Long timeout;
    @Value("${jwt.refresh-timeout:604800000}") // 默认7天（毫秒）
    private Long refreshTimeout;

    /**
     * 获取签名密钥
     */
    private SecretKey getSigningKey() {
        return Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 生成访问令牌（Access Token）
     */
    public String generateToken(Long userId) {
        return generateToken(userId, timeout, TOKEN_TYPE_ACCESS);
    }

    /**
     * 生成刷新令牌（Refresh Token）
     */
    public String generateRefreshToken(Long userId) {
        return generateToken(userId, refreshTimeout, TOKEN_TYPE_REFRESH);
    }

    /**
     * 生成JWT令牌的核心方法
     */
    private String generateToken(Long userId, Long expireTime, String tokenType) {
        Date now = new Date();
        Date expireAt = new Date(now.getTime() + expireTime);

        return Jwts.builder()
                .subject(userId.toString())
                .issuedAt(now)
                .expiration(expireAt)
                .claim("type", tokenType)
                .claim("userId", userId)
                .signWith(getSigningKey(), Jwts.SIG.HS512)
                .compact();
    }

    /**
     * 获取访问令牌过期时间（秒）
     */
    public Long getExpirationTime() {
        return timeout / 1000;
    }

    /**
     * 获取刷新令牌过期时间（秒）
     */
    public Long getRefreshExpirationTime() {
        return refreshTimeout / 1000;
    }

    /**
     * 解析JWT令牌
     */
    public Claims parse(String token) {
        if (!StringUtils.hasText(token)) {
            return null;
        }
        try {
            return Jwts.parser()
                    .verifyWith(getSigningKey())
                    .build()
                    .parseSignedClaims(token)
                    .getPayload();
        } catch (ExpiredJwtException e) {
            log.warn("Token已过期: {}", e.getMessage());
        } catch (UnsupportedJwtException e) {
            log.warn("不支持的JWT: {}", e.getMessage());
        } catch (MalformedJwtException e) {
            log.warn("JWT格式错误: {}", e.getMessage());
        } catch (JwtException e) {
            log.warn("JWT签名验证失败: {}", e.getMessage());
        } catch (IllegalArgumentException e) {
            log.warn("JWT参数异常: {}", e.getMessage());
        }
        return null;
    }

    /**
     * 验证JWT令牌是否有效
     */
    public boolean validateToken(String token) {
        return parse(token) != null;
    }

    /**
     * 验证访问令牌
     */
    public boolean validateAccessToken(String token) {
        Claims claims = parse(token);
        if (claims == null) {
            return false;
        }
        String tokenType = (String) claims.get("type");
        return TOKEN_TYPE_ACCESS.equals(tokenType);
    }

    /**
     * 验证刷新令牌
     */
    public boolean validateRefreshToken(String token) {
        Claims claims = parse(token);
        if (claims == null) {
            return false;
        }
        String tokenType = (String) claims.get("type");
        return TOKEN_TYPE_REFRESH.equals(tokenType);
    }

    /**
     * 从JWT令牌中获取用户ID
     */
    public Long getUserIdFromToken(String token) {
        Claims claims = parse(token);
        if (claims == null) {
            return null;
        }

        // 优先从userId claim获取
        Object userIdClaim = claims.get("userId");
        if (userIdClaim != null) {
            if (userIdClaim instanceof Integer) {
                return ((Integer) userIdClaim).longValue();
            } else if (userIdClaim instanceof Long) {
                return (Long) userIdClaim;
            }
        }

        // 降级到从subject获取
        try {
            return Long.valueOf(claims.getSubject());
        } catch (NumberFormatException e) {
            log.warn("无法从token中解析用户ID: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 获取令牌类型
     */
    public String getTokenType(String token) {
        Claims claims = parse(token);
        return claims != null ? (String) claims.get("type") : null;
    }

    /**
     * 检查JWT令牌是否过期
     */
    public boolean isTokenExpired(String token) {
        Claims claims = parse(token);
        if (claims == null) {
            return true;
        }
        Date expiration = claims.getExpiration();
        return expiration.before(new Date());
    }

    /**
     * 获取令牌剩余有效时间（秒）
     */
    public long getRemainingTime(String token) {
        Claims claims = parse(token);
        if (claims == null) {
            return 0;
        }

        Date expiration = claims.getExpiration();
        Date now = new Date();

        if (expiration.before(now)) {
            return 0;
        }

        return (expiration.getTime() - now.getTime()) / 1000;
    }

    /**
     * 刷新访问令牌
     */
    public String refreshAccessToken(String refreshToken) {
        if (!validateRefreshToken(refreshToken)) {
            log.warn("刷新令牌无效");
            return null;
        }

        Long userId = getUserIdFromToken(refreshToken);
        if (userId == null) {
            log.warn("无法从刷新令牌中获取用户ID");
            return null;
        }

        return generateToken(userId);
    }
}

